package com.rexolar.openapi.utlis;

import com.alibaba.fastjson.JSONObject;

import java.util.BitSet;
import java.util.Iterator;
import java.util.Map;

public class UrlEncoderUtils {
    private static BitSet dontNeedEncoding;

    static {
        dontNeedEncoding = new BitSet(256);
        int i;
        for (i = 'a'; i <= 'z'; i++) {
            dontNeedEncoding.set(i);
        }
        for (i = 'A'; i <= 'Z'; i++) {
            dontNeedEncoding.set(i);
        }
        for (i = '0'; i <= '9'; i++) {
            dontNeedEncoding.set(i);
        }
        dontNeedEncoding.set('+');
        /**
         * 这里会有误差,比如输入一个字符串 123+456,它到底是原文就是123+456还是123 456做了urlEncode后的内容呢？<br>
         * 其实问题是一样的，比如遇到123%2B456,它到底是原文即使如此，还是123+456 urlEncode后的呢？ <br>
         * 在这里，我认为只要符合urlEncode规范的，就当作已经urlEncode过了<br>
         * 毕竟这个方法的初衷就是判断string是否urlEncode过<br>
         */

        dontNeedEncoding.set('-');
        dontNeedEncoding.set('_');
        dontNeedEncoding.set('.');
        dontNeedEncoding.set('*');
    }

    /**
     * 判断str是否urlEncoder.encode过<br>
     * 经常遇到这样的情况，拿到一个URL,但是搞不清楚到底要不要encode.<Br>
     * 不做encode吧，担心出错，做encode吧，又怕重复了<Br>
     *
     * @param str
     * @return
     */
    public static boolean hasUrlEncoded(String str) {

        /**
         * 支持JAVA的URLEncoder.encode出来的string做判断。 即: 将' '转成'+' <br>
         * 0-9a-zA-Z保留 <br>
         * '-'，'_'，'.'，'*'保留 <br>
         * 其他字符转成%XX的格式，X是16进制的大写字符，范围是[0-9A-F]
         */
        boolean needEncode = false;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (dontNeedEncoding.get((int) c)) {
                continue;
            }
            if (c == '%' && (i + 2) < str.length()) {
                // 判断是否符合urlEncode规范
                char c1 = str.charAt(++i);
                char c2 = str.charAt(++i);
                if (isDigit16Char(c1) && isDigit16Char(c2)) {
                    continue;
                }
            }
            // 其他字符，肯定需要urlEncode
            needEncode = true;
            break;
        }

        return !needEncode;
    }

    /**
     * 判断c是否是16进制的字符
     *
     * @param c
     * @return
     */
    private static boolean isDigit16Char(char c) {
        return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F');
    }

    public static void main(String[] args) throws Exception {
        String params = "{\"platformThanksFee\":\"0\",\"sign\":\"d97b4fd0246cedfd18a1aa0f61b6ab89\",\"endLat\":\"23.3721210\",\"endPlanStartTime\":\"2021-11-01 16:55:00\",\"endAdCode\":\"440507\",\"appKey\":\"tytx-T8odQR1X\",\"timestamp\":\"2021-11-01 15:39:49\",\"endShortAddr\":\"%E6%B1%95%E5%A4%B4%E7%AB%99\",\"startLat\":\"23.6646060\",\"partnerGuid\":\"SFC617F99C5500608427F\",\"passengerPrice\":\"4950\",\"planStartTime\":\"2021-11-01 16:55:00\",\"startAdCode\":\"445102\",\"method\":\"sfc.call.order.withBonus\",\"endLon\":\"116.7553570\",\"passengerCount\":\"1\",\"startLongAddr\":\"%E6%B9%98%E6%A1%A5%E5%8C%BA%E7%8E%AF%E5%9F%8E%E8%A5%BF%E8%B7%AF%28%E6%BD%AE%E5%B7%9E%E8%A5%BF%E9%97%A8%E5%8F%A4%E8%BD%A6%E7%AB%99%29\",\"startCityCode\":\"0768\",\"poolStatus\":\"2\",\"endCityCode\":\"0754\",\"token\":\"72296f3191f146bc83072503a523498c\",\"mobilePhone\":\"18574739435\",\"startLon\":\"116.6426162\",\"startPlanStartTime\":\"2021-11-01 16:25:00\",\"endLongAddr\":\"%E6%B1%95%E5%A4%B4%E7%AB%99\",\"thanksFee\":\"0\",\"startShortAddr\":\"%E6%BD%AE%E5%B7%9E%E8%A5%BF%E9%97%A8%E5%8F%A4%E8%BD%A6%E7%AB%99\"}";
        JSONObject jsonParams = JSONObject.parseObject(params);
        Iterator iter = jsonParams.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            if(entry.getValue().toString().contains("%")){
                if(UrlEncoderUtils.hasUrlEncoded(entry.getValue().toString())){
                    System.out.println(true);
                    break;
                }
            }
        }
        System.out.println(hasUrlEncoded("我是"));
    }
}
